package it.traveldreamWeb.employee;

import it.traveldream.beans.ExcursionManagerInterface;
import it.traveldream.beans.HotelManagerInterface;
import it.traveldream.beans.PackageManagerInterface;
import it.traveldream.beans.TransportMeanManagerInterface;
import it.traveldream.dto.ExcursionDTO;
import it.traveldream.dto.HotelDTO;
import it.traveldream.dto.HotelDTO.HotelRoomType;
import it.traveldream.dto.LocationDTO;
import it.traveldream.dto.TPDTO;
import it.traveldream.dto.TransportMeanDTO;
import it.traveldream.exceptions.InvalidTPException;
import it.traveldream.exceptions.LocationNotFoundException;
import it.traveldream.exceptions.ProductNotFoundException;
import it.traveldream.exceptions.TPNotFoundException;
import it.traveldreamWeb.shared.ApplicationDataBean;
import it.traveldreamWeb.shared.ExcursionDataModel;
import it.traveldreamWeb.shared.HotelDataModel;
import it.traveldreamWeb.shared.HotelRoom;
import it.traveldreamWeb.shared.MeanDataModel;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;


@ManagedBean(name="packageBean")
@ViewScoped
public class PackageBean {

	@EJB
	private PackageManagerInterface TPManager;
	@EJB
	private TransportMeanManagerInterface meanManager;
	@EJB
	private HotelManagerInterface hotelManager;
	@EJB
	private ExcursionManagerInterface exManager;

	@ManagedProperty(value="#{eSessionBean}")
	private EmployeeSessionBean session;

	private TPDTO myTP;
	private Long TPId;
	private Long locationId;
	private String error;

	private MeanDataModel meanDataModel;
	private HotelDataModel hotelDataModel;
	private ExcursionDataModel exsDataModel;
	private ExcursionDTO[] selectedExs;

	@ManagedProperty(value="#{applicationDataBean}")
	private ApplicationDataBean appData;

	public PackageBean() {
		this.myTP = new TPDTO();	
	}

	public void init(){
		try {
			if (this.TPId != null){
				this.myTP.setTPId(this.TPId);
				this.myTP = this.TPManager.getTP(this.myTP);

				List<TransportMeanDTO> means = this.TPManager.getAlternativeMeans(this.myTP);
				means.add(this.myTP.getMean());
				this.meanDataModel = new MeanDataModel(means);

				List<HotelDTO> hotels = this.TPManager.getAlternativeHotels(this.myTP);
				hotels.add(this.myTP.getHotel());
				this.hotelDataModel = new HotelDataModel(hotels);

				this.selectedExs = new ExcursionDTO[this.myTP.getExcursions().size()];
				this.selectedExs = this.myTP.getExcursions().toArray(this.selectedExs);
				ArrayList<ExcursionDTO> allExs = new ArrayList<>(this.TPManager.getAlternativeExcursions(this.myTP));
				allExs.addAll(this.myTP.getExcursions());
				this.exsDataModel = new ExcursionDataModel(allExs);
			} else if (this.locationId != null){
				LocationDTO location = null;
				for (LocationDTO l : this.appData.getLocations()){
					if (l.getLocationId().equals(this.locationId))
						location = l;
				}

				this.meanDataModel = new MeanDataModel(this.meanManager.getMeansByLocation(location));
				this.hotelDataModel = new HotelDataModel(this.hotelManager.getHotelsByLocation(location));
				this.exsDataModel = new ExcursionDataModel(this.exManager.getExcursionsByLocation(location));
			} else {
				ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();
				try {
					String path = context.getRequestContextPath()+context.getRequestServletPath();
					context.redirect(path.replace("PackageCreation.xhtml", "home.xhtml"));
				} catch (IOException e) {
					throw new RuntimeException();
				}
			}
		} catch (TPNotFoundException e) {
			this.setError("Invalid request. Wrong travel package?");
		} catch (LocationNotFoundException e) {
			this.setError("Invalid request. Wrong location?");
		} catch (Exception e){
			this.setError("Internal error. Please try again");
		}

	}

	public String addPackage() {
		if (this.locationId != null){
			if (this.myTP.getMean() == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
						"Select one transport mean");
				msg.setSeverity(FacesMessage.SEVERITY_ERROR);
				FacesContext.getCurrentInstance().addMessage("form:meanTable", msg);
				return null;
			}
			if (this.myTP.getHotel() == null){
				FacesMessage msg = new FacesMessage("Validation failed.", 
						"Select one hotel");
				msg.setSeverity(FacesMessage.SEVERITY_ERROR);
				FacesContext.getCurrentInstance().addMessage("form:hotelTable", msg);
				return null;
			}

			try {
				List<ExcursionDTO> excursions = Arrays.asList(this.selectedExs);
				this.myTP.setExcursions(excursions);

				this.TPManager.saveTP(this.myTP);
				this.session.setSuccessMessage("Travel package created!");
				return "home?faces-redirect=true";
			} catch (ProductNotFoundException | InvalidTPException e) {
				this.setError("Invalid products or composition");
				return null;
			} catch (Exception e){
				this.setError("Internal error. Please try again");
				return null;
			}
		}
		return null;
	}

	public String modifyPackage(){
		if (this.TPId != null){
			try {
				List<ExcursionDTO> excursions = Arrays.asList(this.selectedExs);
				this.myTP.setExcursions(excursions);

				this.TPManager.updateTP(this.myTP);
				this.session.setSuccessMessage("Travel package updated!");
				return "home?faces-redirect=true";
			} catch (ProductNotFoundException | InvalidTPException e) {
				this.setError("Invalid products or composition");
				return null;
			} catch (Exception e){
				this.setError("Internal error. Please try again");
				return null;
			}
		}
		return null;
	}
	public List<LocationDTO> getLocations(){
		return this.appData.getLocations();
	}

	public Long getTPId() {
		return this.TPId;
	}

	public void setTPId(Long tPId) {
		this.TPId = tPId;
	}

	public Long getLocationId() {
		return this.locationId;
	}

	public void setLocationId(Long locationId) {
		this.locationId = locationId;
	}

	public void setAppData(ApplicationDataBean appData) {
		this.appData = appData;
	}

	public String getError() {
		return this.error;
	}

	public void setError(String error) {
		this.error = error;
	}

	public TPDTO getMyTP() {
		return this.myTP;
	}

	public void setMyTP(TPDTO myTP) {
		this.myTP = myTP;
	}	

	public List<HotelRoom> getRoomsAsList(HotelDTO hotel){
		if (hotel != null){
			List<HotelRoom> list = new ArrayList<>();
			HotelRoom current;
			for (HotelRoomType type : hotel.getRooms().keySet()){
				current = new HotelRoom();

				current.setTotalRooms(hotel.getRooms().get(type));
				current.setPrice(hotel.getPrices().get(type));
				current.setType(type);
				current.setSelectedRooms(0);
				list.add(current);
			}
			return list;
		} 
		return null;
	}

	public ExcursionDataModel getExsDataModel() {
		return this.exsDataModel;
	}

	public void setExsDataModel(ExcursionDataModel exsDataModel) {
		this.exsDataModel = exsDataModel;
	}

	public ExcursionDTO[] getSelectedExs() {
		return this.selectedExs;
	}

	public void setSelectedExs(ExcursionDTO[] selectedExs) {
		this.selectedExs = selectedExs;
	}

	public MeanDataModel getMeanDataModel() {
		return this.meanDataModel;
	}

	public void setMeanDataModel(MeanDataModel meanDataModel) {
		this.meanDataModel = meanDataModel;
	}

	public HotelDataModel getHotelDataModel() {
		return this.hotelDataModel;
	}

	public void setHotelDataModel(HotelDataModel hotelDataModel) {
		this.hotelDataModel = hotelDataModel;
	}

	public void setSession(EmployeeSessionBean session) {
		this.session = session;
	}
}
